package com.cbs.android.component.binaryutils;

import android.annotation.TargetApi;
import android.os.Build;

import com.cbs.android.component.log.L;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * Created by broche on 4/22/14.
 */
public final class BinaryUtils {
    private static final String TAG = BinaryUtils.class.getName();

    public static byte[] gzip(byte[] data) {
        byte[] result = null;
        ByteArrayInputStream byteArrayInputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        GZIPOutputStream gzipOutputStream = null;
        try {
            byteArrayInputStream = new ByteArrayInputStream(data);
            byteArrayOutputStream = new ByteArrayOutputStream();
            gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
            byte[] buffer = new byte[2048];
            int readSize;
            while (-1 != (readSize = byteArrayInputStream.read(buffer, 0, buffer.length))) {
                gzipOutputStream.write(buffer, 0, readSize);
            }
            gzipOutputStream.finish();
            result = byteArrayOutputStream.toByteArray();
            byteArrayOutputStream.flush();
        } catch (IOException e) {
            L.e(TAG, "", e);
        } finally {
            if (byteArrayInputStream != null) {
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    L.e(TAG, "", e);
                }
            }
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    L.e(TAG, "", e);
                }
            }
            if (gzipOutputStream != null) {
                try {
                    gzipOutputStream.close();
                } catch (IOException e) {
                    L.e(TAG, "", e);
                }
            }
        }
        return result;
    }

    public static byte[] ungzip(byte[] data) {
        byte[] result = null;
        ByteArrayInputStream byteArrayInputStream = null;
        GZIPInputStream gzipInputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            byteArrayInputStream = new ByteArrayInputStream(data);
            gzipInputStream = new GZIPInputStream(byteArrayInputStream);
            byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[2048];
            int readSize;
            while (-1 != (readSize = gzipInputStream.read(buffer, 0, buffer.length))) {
                byteArrayOutputStream.write(buffer, 0, readSize);
            }
            byteArrayOutputStream.flush();
            result = byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            L.e(TAG, "", e);
        } finally {
            if (gzipInputStream != null) {
                try {
                    gzipInputStream.close();
                } catch (IOException e) {
                    L.e(TAG, "", e);
                }
            }
            if (byteArrayInputStream != null) {
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    L.e(TAG, "", e);
                }
            }
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    L.e(TAG, "", e);
                }
            }
        }
        return result;
    }

    @TargetApi(Build.VERSION_CODES.FROYO)
    public static byte[] base64Encode(byte[] data) {
        return android.util.Base64.encode(data, android.util.Base64.DEFAULT);
    }

    @TargetApi(Build.VERSION_CODES.FROYO)
    public static byte[] base64Encode(byte[] data, int flags) {
        return android.util.Base64.encode(data, flags);
    }

    @TargetApi(Build.VERSION_CODES.FROYO)
    public static byte[] base64Decode(byte[] data) {
        return android.util.Base64.decode(data, android.util.Base64.DEFAULT);
    }

    @TargetApi(Build.VERSION_CODES.FROYO)
    public static byte[] base64Decode(byte[] data, int flags) {
        return android.util.Base64.decode(data, flags);
    }

    private final static String HMAC_SHA1 = "HmacSHA1";

    public static byte[] hmacSHA1(byte[] data, byte[] key) {
        byte[] result = null;
        SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA1);
        try {
            Mac mac = Mac.getInstance(HMAC_SHA1);
            mac.init(signingKey);
            result = mac.doFinal(data);
        } catch (NoSuchAlgorithmException e) {
            L.e(TAG, "", e);
        } catch (InvalidKeyException e) {
            L.e(TAG, "", e);
        }
        return result;
    }

    private final static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public static String md5(byte[] data) {
        String result = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(data);
            byte[] bresult = md.digest();
            result = bytes2String(bresult);
        } catch (NoSuchAlgorithmException e) {
            L.e(BinaryUtils.class.getName(), e.getMessage());
        }
        return result;
    }

    private static String bytes2String(byte[] data) {
        char[] c = new char[data.length * 2];
        for (int i = 0; i <= data.length - 1; i++) {
            byte b = data[i];
            c[i * 2] = hexDigits[b >> 4 & 0xF];
            c[i * 2 + 1] = hexDigits[b & 0xF];
        }
        return new String(c);
    }
}